﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;
using Assist;
using Autodesk.Revit.DB;
using Autodesk.Revit.DB.Architecture;
using YJKSparseDistance.Properties;
using YJKInspectModelFunc;
using YJKInspectModelFunc.ModelLayer;

namespace YJKSparseDistance.ModelLayer
{
	public class RoomPacker_EvacuationDistance : BaseRoomPacker
	{
		public bool IfIsRunWayRoomByName
		{
			get
			{
				return this.m_IfIsRunWayRoomByName;
			}
		}

		public StairRoomKindEnum ThisKindEnum
		{
			get
			{
				return this.m_thisKindEnum;
			}
			set
			{
				if (value != StairRoomKindEnum.None)
				{
					this.SetAsStarisRoom();
				}
				if (this.m_thisKindEnum != StairRoomKindEnum.Open)
				{
					this.m_thisKindEnum = value;
				}
			}
		}

		public AreaPacker_EvacuationDistance ParentAreaPacker
		{
			get
			{
				return this.m_ParentAreaPacker;
			}
			set
			{
				this.m_ParentAreaPacker = value;
				if (this.m_IfIsRunWayRoomByName)
				{
					this.m_ParentAreaPacker.LstAllRunWayRoom.Add(this);
					this.m_ParentAreaPacker.LstAllRunWayRoom = this.m_ParentAreaPacker.LstAllRunWayRoom.Distinct<RoomPacker_EvacuationDistance>().ToList<RoomPacker_EvacuationDistance>();
				}
			}
		}

		public bool IfIsRunWayRoom
		{
			get
			{
				return this.m_IfIsRunWayRoom;
			}
		}

		public bool IfStrairsRoom
		{
			get
			{
				return this.m_IfStrairsRoom;
			}
			private set
			{
				this.m_IfStrairsRoom = value;
			}
		}

		public bool IfStrairsRoomDoorToOutSide
		{
			get
			{
				return this.m_IfStrairsRoomDoorToOutSide;
			}
			private set
			{
				this.m_IfStrairsRoomDoorToOutSide = value;
			}
		}

		public List<KeyValuePair<ObstructurePacker_EvacuationDistance, XYZ>> AllStairs
		{
			get
			{
				return this.m_AllStairs;
			}
			private set
			{
				this.m_AllStairs = value;
			}
		}

		public List<BaseDoorPacker> StairRoomDoors
		{
			get
			{
				return this.m_StairRoomDoors;
			}
			private set
			{
				this.m_StairRoomDoors = value;
			}
		}

		public List<List<BaseDoorPacker>> AllOutSideDoor
		{
			get
			{
				return this.m_AllOutSideDoor;
			}
			private set
			{
				this.m_AllOutSideDoor = value;
			}
		}

		public RoomPacker_EvacuationDistance(Room inputValue, RevitLinkInstance useLinkInstance = null) : base(inputValue, useLinkInstance)
		{
			if (RoomPacker_EvacuationDistance.m_lstStrRunWayRoomKeyName == null)
			{
				RoomPacker_EvacuationDistance.m_lstStrRunWayRoomKeyName = Resources.Strs_RunWayKeyNames.Split(new char[]
				{
					','
				}).ToList<string>();
			}
			foreach (string pattern in RoomPacker_EvacuationDistance.m_lstStrRunWayRoomKeyName)
			{
				if (Regex.IsMatch(base.ThisRoom.Name, pattern))
				{
					this.m_IfIsRunWayRoomByName = true;
					this.m_IfIsRunWayRoom = true;
					break;
				}
			}
		}

		public List<EndPointPacker> GetAllStartPointPacker()
		{
			List<EndPointPacker> list = new List<EndPointPacker>();
			List<BaseDoorPacker> allEvacuationDoor = this.GetAllEvacuationDoor();
			double nowDownZ = base.NowDownZ;
			double num = double.Parse(Resources.Str_SixH);
			num = AssistFunc.mmToFeet(num);
			Room room = null;
			foreach (BaseDoorPacker baseDoorPacker in allEvacuationDoor)
			{
				room = null;
				if (baseDoorPacker is DoorPacker_EvacuationDistance && baseDoorPacker is DoorPacker_EvacuationDistance && baseDoorPacker.ThisLimitGeometryPacker.IfCanUse && (baseDoorPacker.LstConctRooms.Count != 2 || !(baseDoorPacker.LstConctRooms[0] as RoomPacker_EvacuationDistance).IfIsRunWayRoom || !(baseDoorPacker.LstConctRooms[1] as RoomPacker_EvacuationDistance).IfIsRunWayRoom))
				{
					foreach (BaseRoomPacker baseRoomPacker in baseDoorPacker.LstConctRooms)
					{
						if (baseRoomPacker.ElementId != base.ElementId)
						{
							room = baseRoomPacker.ThisRoom;
						}
					}
					if (room == null)
					{
						room = base.ThisRoom;
					}
					XYZ appendEndPoint = this.CalculateNearMidPoint(baseDoorPacker);
                    XYZ amovePointForDoorToRoom = YJKInspectModelFunc.Utility.GetAMovePointForDoorToRoom(baseDoorPacker, base.ThisRoom, num);
					list.Add(new EndPointPacker(baseDoorPacker, room, amovePointForDoorToRoom, appendEndPoint, true, this.ParentAreaPacker.IfSparay, false));
				}
			}
			return list;
		}

		public List<EndPointPacker> GetAllEndPointPacker()
		{
			List<EndPointPacker> list = new List<EndPointPacker>();
			if (this.ParentAreaPacker != null)
			{
				double nowDownZ = base.NowDownZ;
				foreach (List<BaseDoorPacker> list2 in this.AllOutSideDoor)
				{
					foreach (BaseDoorPacker baseDoorPacker in list2)
					{
						if (baseDoorPacker is DoorPacker_EvacuationDistance && baseDoorPacker is DoorPacker_EvacuationDistance && baseDoorPacker.ThisLimitGeometryPacker.IfCanUse)
						{
							XYZ useEndPoint = this.CalculateNearMidPoint(baseDoorPacker);
							list.Add(new EndPointPacker(baseDoorPacker, base.ThisRoom, useEndPoint, null, false, this.ParentAreaPacker.IfSparay, false));
						}
					}
				}
				if (!this.ParentAreaPacker.IfIsEvacuation)
				{
					foreach (KeyValuePair<ObstructurePacker_EvacuationDistance, XYZ> keyValuePair in this.m_AllStairs)
					{
						XYZ useEndPoint = new XYZ(keyValuePair.Value.X, keyValuePair.Value.Y, nowDownZ);
						list.Add(new EndPointPacker(keyValuePair.Key, base.ThisRoom, useEndPoint, null, false, this.ParentAreaPacker.IfSparay, true));
					}
					foreach (BaseDoorPacker baseDoorPacker2 in this.StairRoomDoors)
					{
						if (baseDoorPacker2 is DoorPacker_EvacuationDistance && baseDoorPacker2 is DoorPacker_EvacuationDistance && baseDoorPacker2.ThisLimitGeometryPacker.IfCanUse)
						{
							XYZ useEndPoint = this.CalculateNearMidPoint(baseDoorPacker2);
							list.Add(new EndPointPacker(baseDoorPacker2, base.ThisRoom, useEndPoint, null, false, this.ParentAreaPacker.IfSparay, false));
						}
					}
				}
			}
			return list;
		}

		public List<List<BaseDoorPacker>> GetGroupedEvacuationDoors()
		{
			List<List<BaseDoorPacker>> list = new List<List<BaseDoorPacker>>();
			foreach (IGrouping<int, BaseDoorPacker> source in from k in this.GetAllEvacuationDoor()
			group k by k.LstConctRooms[0].ThisElementPackerId + k.LstConctRooms[1].ThisElementPackerId - base.ThisElementPackerId)
			{
				list.Add(new List<BaseDoorPacker>());
				list[list.Count - 1].AddRange(source.ToList<BaseDoorPacker>());
			}
			return list;
		}

		public XYZ CalculateNearMidPoint(BaseDoorPacker tempDoorPacker)
		{
			XYZ result = (tempDoorPacker as DoorPacker_EvacuationDistance).ArrayTwoSideMidPoint[0];
			if (base.ThisRoom.IsPointInRoom((tempDoorPacker as DoorPacker_EvacuationDistance).ArrayTwoSideMidPoint[1]))
			{
				result = (tempDoorPacker as DoorPacker_EvacuationDistance).ArrayTwoSideMidPoint[1];
			}
			return result;
		}

		public void SetAsRunWayRoom()
		{
			this.m_IfIsRunWayRoom = true;
			if (this.AllOutSideDoor.Count == 0)
			{
				List<BaseDoorPacker> list = new List<BaseDoorPacker>();
				foreach (BaseDoorPacker baseDoorPacker in base.LstBaseDoorPacker)
				{
                    if (YJKInspectModelFunc.Utility.IfDoorIsOutSideDoor(baseDoorPacker))
					{
						list.Add(baseDoorPacker);
					}
				}
				double num = double.Parse(Resources.Str_FiveMeter) * double.Parse(Resources.Str_OneK);
				num = AssistFunc.mmToFeet(num);
                this.AllOutSideDoor = YJKInspectModelFunc.Utility.GroupDoorsByDistance(list, num, null);
			}
			if (this.AllStairs.Count == 0 && this.ThisKindEnum == StairRoomKindEnum.Open)
			{
				foreach (KeyValuePair<BaseHostInRoomPacker, XYZ> keyValuePair in base.LstHostElementPacker)
				{
					if (keyValuePair.Key is ObstructurePacker_EvacuationDistance && keyValuePair.Key is ObstructurePacker_EvacuationDistance && (keyValuePair.Key as ObstructurePacker_EvacuationDistance).IfStairs)
					{
						this.m_AllStairs.Add(new KeyValuePair<ObstructurePacker_EvacuationDistance, XYZ>(keyValuePair.Key as ObstructurePacker_EvacuationDistance, keyValuePair.Value));
					}
				}
			}
		}

		internal void SetAsRunWayRoom(RoomPacker_EvacuationDistance stairRoom)
		{
			DoorPackerCompare comparer = new DoorPackerCompare();
			if (base.RoomId != stairRoom.RoomId)
			{
				foreach (BaseDoorPacker baseDoorPacker in stairRoom.LstBaseDoorPacker)
				{
					if (base.LstBaseDoorPacker.Contains(baseDoorPacker, comparer))
					{
						this.StairRoomDoors.Add(baseDoorPacker);
					}
				}
				this.StairRoomDoors = this.StairRoomDoors.Distinct(comparer).ToList<BaseDoorPacker>();
			}
			this.SetAsRunWayRoom();
		}

		internal void SetAsRunWayRoom(BaseDoorPacker stairRoomDoor)
		{
			DoorPackerCompare comparer = new DoorPackerCompare();
			this.StairRoomDoors.Add(stairRoomDoor);
			this.StairRoomDoors = this.StairRoomDoors.Distinct(comparer).ToList<BaseDoorPacker>();
			this.SetAsRunWayRoom();
		}

		private void CalculateDoorTwoPoint(double nowZ, double moveValue, BaseDoorPacker tempDoorPacker, out XYZ originPoint, out XYZ movedPoint)
		{
			originPoint = tempDoorPacker.ThisLimitGeometryPacker.CenterPoint;
            movedPoint = YJKInspectModelFunc.Utility.GetAMovePointForDoorToRoom(tempDoorPacker, base.ThisRoom, moveValue);
			originPoint = new XYZ(originPoint.X, originPoint.Y, nowZ);
			movedPoint = new XYZ(movedPoint.X, movedPoint.Y, nowZ);
		}

		private List<BaseDoorPacker> GetAllEvacuationDoor()
		{
			List<BaseDoorPacker> list = new List<BaseDoorPacker>();
			DoorPackerCompare comparer = new DoorPackerCompare();
			foreach (BaseDoorPacker baseDoorPacker in base.LstBaseDoorPacker)
			{
				if (baseDoorPacker.LstConctRooms.Count > 1 && !this.StairRoomDoors.Contains(baseDoorPacker, comparer))
				{
					list.Add(baseDoorPacker);
				}
			}
			return list;
		}

		private void SetAsStarisRoom()
		{
			if (StairRoomKindEnum.None == this.m_thisKindEnum)
			{
				return;
			}
			this.IfStrairsRoom = true;
			foreach (BaseDoorPacker inputPacker in base.LstBaseDoorPacker)
			{
                bool flag = YJKInspectModelFunc.Utility.IfDoorToRoom(inputPacker, base.ThisRoom);
				this.IfStrairsRoomDoorToOutSide = (this.IfStrairsRoomDoorToOutSide && !flag);
			}
		}

		private bool m_IfIsRunWayRoomByName;

		private bool m_IfIsRunWayRoom;

		private bool m_IfStrairsRoom;

		private bool m_IfStrairsRoomDoorToOutSide = true;

		private AreaPacker_EvacuationDistance m_ParentAreaPacker;

		private StairRoomKindEnum m_thisKindEnum = StairRoomKindEnum.None;

		private List<List<BaseDoorPacker>> m_AllOutSideDoor = new List<List<BaseDoorPacker>>();

		private List<KeyValuePair<ObstructurePacker_EvacuationDistance, XYZ>> m_AllStairs = new List<KeyValuePair<ObstructurePacker_EvacuationDistance, XYZ>>();

		private List<BaseDoorPacker> m_StairRoomDoors = new List<BaseDoorPacker>();

		private static List<string> m_lstStrRunWayRoomKeyName;
	}
}
